﻿using System.Collections.Generic;

namespace Core.STL
{
    public interface IReadOnlyKeyList<K, T>
    {
        public int Count { get; }

        public T GetByIndex(int index);

        public T GetByKey(K key);
    }

    public class KeyList<K, T> : IReadOnlyKeyList<K, T>
    {
        private readonly List<T> list = new();

        private readonly Dictionary<K, int> key2IndexDict = new();
        private readonly Dictionary<int, K> index2KeyDict = new();

        public int Count => list.Count;

        public T GetByIndex(int index)
        {
            if (index < 0 || index >= list.Count)
            {
                return default;
            }
            return list[index];
        }

        public T GetByKey(K key)
        {
            if (!key2IndexDict.ContainsKey(key))
            {
                return default;
            }
            int index = key2IndexDict[key];
            return GetByIndex(index);
        }

        public bool Contains(K key)
        {
            return key2IndexDict.ContainsKey(key);
        }

        public void Add(K key, T value)
        {
            if (key2IndexDict.ContainsKey(key))
            {
                int index = key2IndexDict[key];
                list[index] = value;
            }
            else
            {
                list.Add(value);

                int index = list.Count - 1;
                key2IndexDict[key] = index;
                index2KeyDict[index] = key;
            }
        }

        public void Remove(K key)
        {
            if (!key2IndexDict.ContainsKey(key))
            {
                return;
            }
            int index = key2IndexDict[key];
            var t = list[index];
            if (t is IDispose obj)
            {
                obj.Dispose();
            }
            int lastIndex = list.Count - 1;
            if (index == lastIndex)
            {
                list.RemoveAt(lastIndex);
                key2IndexDict.Remove(key);
                index2KeyDict.Remove(lastIndex);
            }
            else
            {
                list[index] = list[lastIndex];
                list.RemoveAt(lastIndex);

                var lastKey = index2KeyDict[lastIndex];
                key2IndexDict.Remove(key);
                key2IndexDict[lastKey] = index;
                index2KeyDict.Remove(lastIndex);
                index2KeyDict[index] = lastKey;
            }
        }

        public void Clear()
        {
            foreach (var element in list)
            {
                if (element is IDispose obj)
                {
                    obj.Dispose();
                }
            }
            list.Clear();
            key2IndexDict.Clear();
            index2KeyDict.Clear();
        }

        //public void Sort()
        //{
        //    list.Sort();

        //    key2IndexDict.Clear();
        //    index2KeyDict.Clear();

        //    //for (int i = 0; i < list.Count; i++)
        //    //{
        //    //    int agentNo = list[i].id;
        //    //    agentNo2indexDict.Add(agentNo, i);
        //    //    index2agentNoDict.Add(i, agentNo);
        //    //}
        //}
    }

}
